<?php
require_once 'models/catalog.inc';
require_once 'models/TCatalogCategoryModel.inc';
require_once 'models/TMSProductImageModel.inc';
require_once 'models/TCatalogProductModel.inc';
require_once 'models/TMSPublicableItemModel.inc';

class TMSNomenclatureItem extends TCandyItem {
	protected $imagesCache;
	
	private $_quantaty_ = false;
	
	private $_reserved_ = false;
	
	private $_is_reserved_ = false;
	
	private $_price_ = false;
	
	private $_kit_price_ = false;
	
	private $_allow_order_ = true;
	
	private $_default_article_ = null;
	
	private $_art_dim_ = null;
	
	private $_art_matrix_ = null;

	private $_discounts_ = null;
	
	private $_discount_ = false;
	
	private function _get_art_matrix(){
		if (is_null($this->_art_matrix_)){
			$this->_art_dim_ = array();
			$this->_art_matrix_ = array();
			
			foreach ($this->Articles as $a)
			{
				if ($a->AllowOrder){
					$m = &$this->_art_matrix_;
					foreach ($a->Properties() as $p){
						if (in_array($p->Name(), array('Article','Price','KitPrice','Added','Nomenclature','Kit','Quantaty','Reserved', 'Active')))
							continue;
					
						if (!isset($this->_art_dim_[$p->Name()]))
							$this->_art_dim_[$p->Name()] = (object)array("caption"=>$p->Caption(),"values"=>array());
					
						$v = (string)$p->Value();
						if ($p->Selection())
							$this->_art_dim_[$p->Name()]->values[$v] = $p->DisplayValue();
						else if  ($p->Type() == TItemPropertyType::PT_REFERENCE)
							$this->_art_dim_[$p->Name()]->values[$v] = (string)$p->ReferedInstance();
						else
							$this->_art_dim_[$p->Name()]->values[$v] = $v;
					
						if (!isset($m[$v]))
							$m[$v] = array();
						$m = &$m[$v];
					}
					$m = array($a->ItemId(),$a->Article,$a->Price,$a->DiscountedPrice);
				}
			}
			foreach ($this->_art_dim_ as $nm=>&$dim){
				asort($dim->values);
			}
		}
	}
	
	private function _cache_images(){
		if (!is_array($this->imagesCache)){
			$this->imagesCache = array();
			foreach ($this->Images as $im)
				$this->imagesCache[] = $im;
		}
	}
	
	private function _get_articleinfo(){
		if ($this->_price_ === false){
			if ($this->ArticleClass == 'TMSGoods' || is_subclass_of($this->ArticleClass, 'TMSGoods')){
				$this->_quantaty_ = 0;
				$this->_reserved_ = 0;
			}
			$this->_is_reserved_ = true;
			$this->_allow_order_ = false;
			$this->_price_ = 0;
			$this->_kit_price_ = 0;
			$this->_default_article_ = null;
			if ($this->Articles){
				foreach ($this->Articles as $a){
					if (!$this->_price_){
						$this->_price_ = $a->Base->Price;
						$this->_kit_price_ = $a->Base->KitPrice;
						$this->_default_article_ = $a;
					}
					
					if (!$this->_allow_order_ && $a->Base->AllowOrder)
						$this->_allow_order_ = true;
					if ($this->_is_reserved_ && $a->Base->State != (string)TMSProductState::ReservedState())
						$this->_is_reserved_ = false;
					if ($a->Base instanceof TMSGoods){
						$this->_quantaty_ += $a->Base->Quantaty;
						$this->_reserved_ += $a->Base->Reserved;
					}
				}
			}
		}
	}
	
	public function __get($nm){
		switch ($nm){
			case 'Cover':{
				$this->_cache_images();
				if (count($this->imagesCache) > 0){
					return $this->imagesCache[0]->Thumbnail;
				}
				return null;
			}break;
			case 'BackCover':{
				$this->_cache_images();
				if (count($this->imagesCache) > 1)
					return $this->imagesCache[1]->Thumbnail;
				return null;
			}break;
			case 'Preview':{
				$this->_cache_images();
				if (count($this->imagesCache) > 0)
					return $this->imagesCache[0]->Preview;
				return null;
			}break;
			case 'Icon':{
				$this->_cache_images();
				if (count($this->imagesCache) > 0)
					return $this->imagesCache[0]->TinyThumbnail;
				return null;
			}break;	
			case 'Quantaty':{
				$this->_get_articleinfo();
				return $this->_quantaty_;
			}break;
			case 'Reserved':{
				$this->_get_articleinfo();
				return $this->_reserved_;
			}break;
			case 'Price':{
				if ($v = parent::__get($nm))
					return $v;
				$this->_get_articleinfo();
				return $this->_price_;
			}break;
			case 'DefaultArticle':{
				$this->_get_articleinfo();
				return $this->_default_article_;
			}break;
			case 'KitPrice':{
				if ($v = parent::__get($nm))
					return $v;
				$this->_get_articleinfo();
				return $this->_kit_price_;
			}break;
			case 'State':{
				if ($this->Quantaty == 0){
					if ($this->UnavailableState)
						return (string)$this->UnavailableState;
					else
						return (string)TMSProductState::UnavailableState();
				} else if ($this->IsReserved)
					return 	(string)TMSProductState::ReservedState();
				return (string)TMSProductState::AvailableState();
			}break;
			case 'AllowOrder':{
				$this->_get_articleinfo();
				return $this->_allow_order_;
			}break;
			case 'ArticleMatrix':{
				$this->_get_art_matrix();
				return $this->_art_matrix_;
			}break;
			case 'ArticleDimensions':{
				$this->_get_art_matrix();
				return $this->_art_dim_;
			}break;
			case 'Discounts':{
				if (!$this->_discounts_)
					$this->_discounts_ = $this->Model->ItemDiscounts($this);
				return $this->_discounts_;
			}break;
			case 'DiscountAmount':{
				if ($this->_discount_ === false){
					$this->_discount_ = 0;
					foreach ($this->Discounts as $d)
						$this->_discount_ += $d->Calculate($p);
				}
				return $this->_discount_;
			}break;
			case 'DiscountedPrice':{
				return ($this->DiscountAmount > 0)?($this->Price - $this->DiscountAmount):null;
			}break;
			default:{
				$v = parent::__get($nm);
				if (is_null($v)){
					$arts = parent::__get('Articles');
					if ($arts)
					foreach ($arts as $a){
						if ($a instanceof IItem)
							$a = $a->Base;
						if ($a->$nm){
							if (is_null($v)) $v = array();
							$v[] = $a->$nm;
						}
					}
					if (is_array($v)){
						sort($v);
						return join(", ",array_unique($v));
					}
					return $v;
				}
				return $v;
			}break;
		}
	}
	
	public function ThumbnailLink(TCandyThumbnailType $type = null){
		return $this->Icon->GetThumbnailLink();
	}
	
	public function FullSizeLink(){
		$this->_cache_images();
		if (count($this->imagesCache) > 0)
			return $this->imagesCache[0]->FullSize->GetLink();
		return null;
	}
	
	public function OrderOptions(){
		$this->_get_articleinfo();
		return $this->_default_article_->OrderOptions();
	}	
	
	public function OrderPrice($kit = false){
		$this->_get_articleinfo();
		return $this->Model->Products->OrderPrice($this->_default_article_,$this,$kit);
	}
}

class TMSNomenclatureModel extends TMSPublicableItemModel {
/**
 * @var TCatalogCategoryModel
 */	
	protected $_ioc_categories_;
	
/**
 * @var TCatalogProductModel
 */	
	protected $_ioc_products_;
	
/**
 * @var TMSDiscountModel
 */
	protected $_ioc_discounts_model_;
	
/**
 * @var TMSNomenclatureDiscountModel
 */	
	protected $_ioc_nomenclature_discounts_model_;
	
	
		
	protected function afterConstruct(){
		$this->_conf_classname_ = 'TMSNomenclature';
	}
	
	public function __get($nm){
		switch ($nm){
			case 'ClassName':{
				if ($fc = $this->forcedNomenclatureClass())
					return $fc;
				return $this->_conf_classname_;
			}break;
			default:return parent::__get($nm);break;
		}
	}	
	
	protected function applyAdditionalDescendants(array $ad = array()){
		return array_merge($ad,$this->Products->AssumedDescendants);
	}
	
	protected function postProcessProperties(){
		parent::postProcessProperties();
		$this->propertyMetas['Quantaty'] = new TOrmPropertyMeta('Quantaty', 'Quantaty', TItemPropertyType::PT_INT,array(),true,true);
		$this->propertyMetas['Reserved'] = new TOrmPropertyMeta('Reserved', 'Reserved', TItemPropertyType::PT_INT,array(),true,true);
		$this->propertyMetas['Added']->ReadOnly = true;
		
		$selection = array();
		$states = $this->Adapter->Fetch(new TMSProductState());
		foreach ($states as $s)
			$selection[$s->Id] = $s->Name;
		
		$this->propertyMetas['UnavailableState']->SetSelection($selection);
		
		if ($this->OrmSettings){
			$ad = $this->OrmSettings->GetValue('TMSArticle.AssumedDescendants');
			$classes = array();
			foreach ($ad as $c)
				if ($caption = $this->OrmSettings->GetValue($c.'.Caption'))
					$classes[$c] = $caption;
				else
					$classes[$c] = $c;
				
			$this->propertyMetas['ArticleClass']->SetSelection($classes);
		}
		
		$this->propertyMetas['PriceLogic']->SetSelection(array(
				TMSNomenclature::PRICE_ADD_KIT => 'Add assembly cost to price',
				TMSNomenclature::PRICE_ONLY_KIT => 'Price equals to assembly cost',
				TMSNomenclature::PRICE_IGNORE_KIT => 'Ignore assembly cost'
		));
		
		if ($this->Categories instanceof TCatalogCategoryModel)
			$this->propertyMetas['Category']->SetSelection($this->Categories->CategoriesList());		
	}
	
	protected function forcedNomenclatureClass(){
		if ($this->OrmSettings)
			return $this->OrmSettings->GetValue('Forced.'.TMSType::BASE_NOMENCLATURE);
		return null;
	}
	
	protected function forcedArticleClass($class = null){
		if ($this->OrmSettings){
			if ($class)
				if ($fc = $this->OrmSettings->GetValue($class.'.Forced'))
					return $fc;
			if ($fc = $this->OrmSettings->GetValue('Forced.'.TMSType::BASE_GOODS))
				return $fc;
			if ($fc = $this->OrmSettings->GetValue('Forced.'.TMSType::BASE_SERVICE))
				return $fc;
		}
		return null;
	}
	
	protected function preCreateItem(array $data, $class = null){
		$fac = $this->forcedArticleClass($class);
		if (!isset($data['ArticleClass']) && !is_null($fac))
			$data['ArticleClass'] = $fac;
		return $data;
	}
	
	protected function postCreateItem(TCandyItem $item,array $data = array()){
		if ($this->Products instanceof TCatalogProductModel)
			$this->Products->CreateItem(array('Nomenclature'=>$item->ItemId()),$item->ArticleClass);
	}
	
	public function CheckItemProperty(TNOrmObject $object, TOrmPropertyMeta $property){
		if (
				$property->Name() == 'Added'
				|| $property->Name() == 'Images'
				|| $property->Name() == 'Kits'
				|| $property->Name() == 'KitSpecifications'
				|| $property->Name() == 'Articles'
				|| $property->Name() == 'Quantaty'
				|| $property->Name() == 'Reserved'
		)
			return !is_null($object->Id);
		
		if ($property->Name() == 'ArticleClass'){
			if ($object->Id)
				$property->ReadOnly = true;
			return is_null($this->forcedArticleClass(get_class($object)));
		}
		return true;
	}	
				
	protected function beforeSave(TNOrmObject $object){
		$object = parent::beforeSave($object);
			if (!$object->Added)
				$object->Added = new TDate();
		return $object;
	}
	
	protected function postEditItem(TCandyItem $item, $origin, array $data = array()){
		parent::postEditItem($item, $origin,$data);
			
		if ($item->Articles->ItemCount() == 1){
			if ($item->Base->Price){
				foreach ($item->Articles as $a){
					if ($a->Base->Price)
						$this->Products->EditItem($a->ItemId(),array("Price"=>0));
				}
			}
		}	
	}
	
	public function  ItemDiscounts(IItem $nomenclature){
		$result = array();
		$explicit = $this->NomenclatureDiscountsModel->NomenclatureDiscounts($nomenclature);
		foreach ($explicit as $d){
			$result[$d->Discount->ItemId()] = $d;
		}

		$a = null;
		foreach ($nomenclature->Articles as $a)
			break;
		
		if ($a){
			$implicit = $this->DiscountsModel->ImplicitProductDiscounts();		
			foreach ($implicit as $d)
				if (!isset($result[$d->ItemId()]))
					if ($d->CanApplyToProduct($a)){
						$result[$d->ItemId()] = $this->NomenclatureDiscountsModel->GetDummyItem();
						$result[$d->ItemId()]->Nomenclature = $nomenclature;
						$result[$d->ItemId()]->Discount = $d;
					}
		}
		return $result;
	}
		
/**
 * @param object $object
 * @return TCandyItem
 */	
	public function WrapObject($object, array &$caller_stack = array()){
		if ($object instanceof $this->_conf_classname_)
			return new TMSNomenclatureItem($object,$this);
		return parent::WrapObject($object,$caller_stack);
	}	
}